// LXH_Data.cpp: implementation of the CLXH_Data class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "LXH_Data.h"
#include "FLOAT.h"
#include <stdio.h>

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CData::CData()
{
	nRow = 0;
	nCol = 0;
	fMat = NULL;
	pNext = NULL;
	pLast = NULL;
	nNRec = 0;
}

CData::CData(int nRow, int nCol)
{
	this->nRow = nRow;
	this->nCol = nCol;
	fMat = NULL;
	pNext = NULL;
	pLast = NULL;
	Alloc();
}

CData::CData(CData &data)
{
	this->nCol = data.nCol;
	this->nRow = data.nRow;
	pNext = NULL;
	pLast = NULL;
	fMat = NULL;
	Alloc();
	for( int i = 0; i < data.nRow; i++ )
		memcpy( fMat[i], data.fMat[i], sizeof(float)*data.nCol );

	CData *pTemp;
	CData *p = data.pNext;
	CData *pCur = this;
	while( p != NULL )
	{
		pCur->pNext = pTemp = new CData( p->nRow, p->nCol );
		for( int i = 0; i < p->nRow; i++ )
			memcpy( pTemp->fMat[i], p->fMat[i], sizeof(float)*p->nCol );
		pCur = pCur->pNext;
		p = p->pNext;
	}
	pLast = pCur;
	this->nNRec = data.nNRec;
}

CData::~CData()
{
	if ( fMat != NULL )	RemoveAll();
}

int CData::GetNRec() {return nNRec;}

BOOL CData::Alloc()
{
	if( fMat != NULL )
	{
		MessageBox(NULL,"Allocation failure 1 in Alloc() : fMat is already allocated", "Error", MB_OK | MB_ICONEXCLAMATION);
		return false;
	}

	fMat = New_FMatrix( nRow, nCol );
	this->nNRec = 1;
	/*char msg[100];
	sprintf(msg,"%d",&nNRec);
	MessageBox(0,msg,0,0);
	*/
	return true;
}

void CData::RemoveAll()
{
	if( fMat != NULL )
	{
		Release_FMatrix( fMat, nRow, nCol );
		fMat = NULL;
	}

	CData *pCur = pNext;
	CData *pTemp;
	while( pCur != NULL )
	{
		//if( pNext!=NULL ) delete pNext;
		Release_FMatrix( pCur->fMat, pCur->nRow, pCur->nCol );
		pCur->fMat = NULL;
		pTemp = pCur;
		pCur = pCur->pNext;
		delete pTemp;
	}

	pNext = NULL;
	pLast = NULL;
	nRow = 0;
	nCol = 0;
	nNRec = 0;
}

void CData::Append(CData &data)
{
	if( this == &data ) 
	{
		CData dt; 
		dt = data;
		Append(dt);
		return;
	}

	if( data.fMat == NULL ) return;

	if( fMat == NULL )
	{
		nRow = data.nRow;
		nCol = data.nCol;
		Alloc();
		for( int i = 0; i < nRow; i++ )
			memcpy( fMat[i], data.fMat[i], nCol * sizeof(float));
	}
	else
	{
		if( pNext == NULL )
			pLast = pNext = new CData;
		else
		{
			pLast->pNext = new CData;
			pLast = pLast->pNext;
		}
		pLast->nCol  = data.nCol;
		pLast->nRow  = data.nRow;
		pLast->pNext = NULL;
		pLast->fMat  = New_FMatrix( data.nRow, data.nCol );
		
		for( int i = 0; i < data.nRow; i++ )
			memcpy( (pLast->fMat)[i], data.fMat[i], data.nCol * sizeof(float));	
		nNRec++;
	}

	CData *p = data.pNext;
	CData *pTemp;
	CData *pCur = pNext == NULL ? this : this->pLast;
	while( p != NULL )
	{
		//if( data.pNext!=NULL ) Append( *(data.pNext) );
		pTemp = new CData(p->nRow, p->nCol);
		for( int i = 0; i < p->nRow; i++ )
			memcpy( pTemp->fMat[i], p->fMat[i], sizeof(float) * p->nCol );
		this->pLast = pCur->pNext = pTemp;
		p = p->pNext;
		pCur = pCur->pNext;
		nNRec++;
	}
}

/*
	The pointer data must not be delete after call this function
*/
void CData::Append(CData *data)
{
	if( data->fMat == NULL ) return;

	if( fMat == NULL )
	{
		nRow = data->nRow;
		nCol = data->nCol;
		Alloc();
		for( int i = 0; i < nRow; i++ )
			memcpy( fMat[i], data->fMat[i], nCol * sizeof(float));
		pLast = pNext = data->pNext;

		CData *p = data->pNext;
		while( p!= NULL ) 
		{
			pLast = p;
			p = p->pNext;
			nNRec++;
		}

		data->pNext = NULL;
		delete data;
	}
	else
	{
		if( pNext == NULL )
			pLast = pNext = data;
		else
		{
			pLast->pNext = data;
			pLast = data;
		}
		nNRec++;
		
		CData *p = data->pNext;
		while( p!= NULL ) 
		{
			pLast = p;
			p = p->pNext;
			nNRec++;
		}
	}
}

float ** CData::New_FMatrix(int nRow, int nCol)
{
	float **fMat = (float **) calloc( nRow, sizeof(float*));
	if ( fMat == NULL) 
	{
		MessageBox(NULL,"Allocation failure 2 in Alloc()", "Error", MB_OK | MB_ICONEXCLAMATION);
		return false;
	}

	for (int i=0; i<nRow; i++)
	{
		fMat[i] = (float *) calloc( nCol, sizeof(float));
		if ( fMat[i] == NULL ) 
		{
			MessageBox(NULL,"Allocation failure 3 in Alloc()", "Error", MB_OK | MB_ICONEXCLAMATION);
			return false;
		}
	}
	return fMat;
}

double ** CData::New_DMatrix(int nRow, int nCol)
{
	double **fMat = (double **) calloc( nRow, sizeof(double*));
	if ( fMat == NULL) 
	{
		MessageBox(NULL,"Allocation failure 2 in Alloc()", "Error", MB_OK | MB_ICONEXCLAMATION);
		return false;
	}

	for (int i=0; i<nRow; i++)
	{
		fMat[i] = (double *) calloc( nCol, sizeof(double));
		if ( fMat[i] == NULL ) 
		{
			MessageBox(NULL,"Allocation failure 3 in Alloc()", "Error", MB_OK | MB_ICONEXCLAMATION);
			return false;
		}
	}
	return fMat;
}

void CData::Release_DMatrix (double **m, int nRow, int nCol)
{	
	for( int i = 0; i < nRow; i++ )
		free(m[i]);
	free(m);
	m = NULL;
}

void CData::Release_FMatrix (float **m, int nRow, int nCol) 
{	
	for( int i = 0; i < nRow; i++ )
		free(m[i]);
	free(m);
	m = NULL;
}

CData* CData::ConCat(CData &data)
{
	if( (data.fMat == NULL)||(fMat == NULL)) 
	{
		MessageBox(NULL,"Error in Concat : fMat is NULL", "Error", MB_OK | MB_ICONEXCLAMATION );
		return NULL;
	}

	if( nNRec != data.nNRec ) 
	{
		MessageBox(NULL,"Error in Concat : Numbers of records are not the same","Error", MB_OK | MB_ICONEXCLAMATION );
		return NULL;
	}

	if( nRow != data.nRow )
	{
		MessageBox(NULL,"Error in Concat : Rows are not the same","Error", MB_OK | MB_ICONEXCLAMATION );
		return NULL;
	}

	CData *pNewData = new CData(nRow, nCol + data.nCol);
	int i;
		
	for( i = 0; i < nRow; i++ )
	{
		memcpy( (pNewData->fMat)[i], fMat[i], nCol * sizeof(float));
		memcpy( (pNewData->fMat)[i]+nCol, data.fMat[i], data.nCol * sizeof(float));
	}
	
	CData *Cur1, *Cur2, *p;
	Cur1 = pNext;
	Cur2 = data.pNext;
	while( Cur1 != NULL )
	{
		if( Cur1->nRow != Cur2->nRow )
		{
			MessageBox(NULL,"Error in Concat : Rows are not the same","Error", MB_OK | MB_ICONEXCLAMATION );
			return NULL;
		}
		
		if( pNewData->pLast == NULL )
			p = pNewData->pLast = pNewData->pNext = new CData;
		else
		{
			pNewData->pLast->pNext = new CData;
			p = pNewData->pLast = pNewData->pLast->pNext;
		}

		p->nCol  = Cur1->nCol + Cur2->nCol;
		p->nRow  = Cur1->nRow;
		p->pNext = NULL;
		p->fMat  = New_FMatrix( p->nRow, p->nCol );

		for( i = 0; i< p->nRow; i++ )
		{
			memcpy( (p->fMat)[i], Cur1->fMat[i], Cur1->nCol * sizeof(float));	
			memcpy( (p->fMat)[i]+ Cur1->nCol, Cur2->fMat[i], Cur2->nCol * sizeof(float));	
		}
		Cur1 = Cur1->pNext;
		Cur2 = Cur2->pNext;
	}

	pNewData->nNRec = this->nNRec;
	return pNewData;
}

void ErrorMsg(char *msg, HWND hwnd)
{
	MessageBox( hwnd, msg, "Error", MB_OK | MB_ICONEXCLAMATION );
	exit(0);
}

void CData::CutFinalPart(CData &data, int nStartIndex)
{
	if( nStartIndex < 0) 
		ErrorMsg( "Error in CutFinalPart : nStartIndex < 0");
	if( nStartIndex >= data.nCol ) return;
	data.nCol = nStartIndex;
	CData *p = data.pNext;
	while( p!=NULL )
	{
		p->nCol = nStartIndex;
		p = p->pNext;
	}
}

void CData::CutFinalPart(int nStartIndex)
{
	if( nStartIndex < 0) 
		ErrorMsg( "Error in CutFinalPart : nStartIndex < 0");
	if( nStartIndex >= nCol ) return;
	nCol = nStartIndex;
	CData *p = pNext;
	while( p!=NULL )
	{
		p->nCol = nStartIndex;
		p = p->pNext;
	}
}

CData &CData::operator=(CData &data)
{
	RemoveAll();
	if( data.fMat == NULL ) return *this;
	nCol = data.nCol;
	nRow = data.nRow;
	Alloc();
	int i,j;
	for( i=0; i<nRow; i++ )
		for( j=0; j<nCol; j++ )
			fMat[i][j] = (data.fMat)[i][j];
	CData *p = data.pNext;
	CData *pTemp;
	while( p!= NULL )
	{
		pTemp = new CData;
		pTemp->nCol = p->nCol;
		pTemp->nRow = p->nRow;
		pTemp->pNext = NULL;
		pTemp->fMat = CData::New_FMatrix( pTemp->nRow, pTemp->nCol );
		for( i=0; i<p->nRow; i++ )
			memcpy( (pTemp->fMat)[i], (p->fMat)[i], p->nCol * sizeof(float) );
		if( pNext == NULL )
		{
			pLast = pNext = pTemp;
		}
		else
		{
			pLast->pNext = pTemp;
			pLast = pTemp;
		}

		p = p->pNext;
	}
	this->nNRec = data.nNRec;
	return *this;
}

void CData::CutFirstPart(CData &data, int nFinalIndex)
{
	CData *p = &data;
	if(( nFinalIndex >= data.nCol )||( nFinalIndex <= 0 )) return;
	if( data.fMat == NULL ) return;
	float **oldMat = NULL;
	int nNewCol = data.nCol - nFinalIndex;

	while( p != NULL )
	{
		oldMat = p->fMat;
		p->fMat = New_FMatrix( p->nRow, nNewCol );
		for( int i=0; i<p->nRow; i++ )
			memcpy( p->fMat[i], oldMat[i] + nFinalIndex, sizeof(float) * nNewCol );
		Release_FMatrix( oldMat, p->nRow, p->nCol );
		p->nCol = nNewCol;
		p = p->pNext;
	}
}

void CData::CutFirstPart(int nFinalIndex)
{
	CData *p = this;
	if(( nFinalIndex >= this->nCol ) || ( nFinalIndex <= 0 )) return;
	if( this->fMat == NULL ) return;
	float **oldMat = NULL;
	int nNewCol = this->nCol - nFinalIndex;

	while( p != NULL )
	{
		oldMat = p->fMat;
		p->fMat = New_FMatrix( p->nRow, nNewCol );
		for( int i=0; i<p->nRow; i++ )
			memcpy( p->fMat[i], oldMat[i] + nFinalIndex, sizeof(float) * nNewCol );
		Release_FMatrix( oldMat, p->nRow, p->nCol );
		p->nCol = nNewCol;
		p = p->pNext;
	}
}

CData * CData::SelectIndex(int index[], int nLen)
{
	if( index == NULL ) 
		ErrorMsg( "Pointer NULL in SelectIndex");
	int i,j;
	CData *p = this->pNext;
	int minLen = this->nCol;
	while( p != NULL )
	{
		if( minLen > p->nCol ) minLen = p->nCol;
		p = p->pNext;
	}

	for( i = 0; i < nLen; i++ )
	{
		if( index[i] >= minLen ) 
			ErrorMsg( "Overflow in SelectIndex" );
	}

	CData *pNew = new CData();
	CData *pTemp;
	p = this;
	while( p != NULL )
	{
		pTemp = new CData( p->nRow, nLen );
		
		for( i = 0; i < p->nRow; i++ )
			for( j = 0; j < nLen; j++ )
				pTemp->fMat[i][j] = p->fMat[i][index[j]];

		pNew->Append( pTemp );
		p = p->pNext;
	}
	return pNew;
}

float CData::GetMax(int *Row, int *Col)
{
	if( fMat == NULL ) 
		ErrorMsg("There no data in the matrix. Error in GetMax function");
	int indexi, indexj;
	float max = - FLT_MAX;
	for( int i = 0; i < nRow; i++ )
	{
		for( int j = 0; j < nCol; j++ )
		{
			if( max < fMat[i][j] )
			{
				max = fMat[i][j];
				indexi = i; indexj = j;
			}
		}
	}

	if( Row != NULL )
	{
		*Row = indexi;
		if( Col != NULL )
			*Col = indexj;
	}
	return max;
}	
